# -*- coding: utf-8 -*-
import re, sys
import mechanize
from BeautifulSoup import BeautifulSoup

url_host = "http://localhost:8080"
url_app = "%s/projectmgr/control" % url_host
filename='test-td-proj.xls'

import pprint
pp = pprint.PrettyPrinter(indent=2)

def applyDict2Form(_br, _form_name, _dict): 
    _br.select_form(name=_form_name)
    f = _br.form
    for kk in _dict: 
        if type(_dict[kk]) is unicode: v = _dict[kk].encode('utf-8')
        elif not _dict.has_key(kk) or _dict[kk] is None: v = ''
        else: v=_dict[kk]
        c=f.find_control(name=kk)
        if c.__class__.__name__=='SelectControl': f[kk]=v and [v] or []
        elif c.__class__.__name__=='HiddenControl': c._value=v
        else: f[kk]=v

def page_get_id_and_soup(page):
    soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
    title = soup.find('div', {'class':'page-title'}) # ok
    id = None
    if title: 
        m = re.search(r'\[([^\]]+)\]', title.find('span').getText())
        if m: id = m.groups()[0]
    print "---> new id %s" % id
    return (id, soup)

def page_get_project_id_and_soup(page):
    soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
    title = soup.find('h1') # ok
    id = None
    if title: 
        m = re.search(r'\[([^\]]+)\]', title.getText())
        if m: id = m.groups()[0]
    print "---> new project id %s" % id
    return (id, soup)


def page_soup_error(soup):
    cm = soup.find('div', {'id':'content-messages'}) # error
    if cm:
        print cm.getText()
        return True
    return False

def page_get_error(page):
    soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
    return page_soup_error(soup)

br = mechanize.Browser()

# login
br.open("%s/login" % url_app)
br.select_form(name="loginform")
br.form['USERNAME']='admin'
br.form['PASSWORD']='ofbiz'
res = br.submit()

mcc = { '_':['master','tasks'],
     'master':{
         'id':['A^1',u'專案ID'],
         'name':['A^2',u'名稱'],
         'desc':['A^3',u'描述'],
         'billing':['A^4',u'客戶的帳務處理'],
         'cust_pm':['C^4',u'客戶PM'],
         'org':['A^5',u'執行單位'],
         'exec_pm':['C^5',u'執行PM'],
         'sa':['E^5',u'系統分析'],
         'pg':['G^5',u'開發人員'],
     },
     'tasks':{
         '*':{
             'id':['A1',u'ID'],
             'sno':['B1',u'序號'],
             'type':['C1',u'種類'],
             'name':['D1',u'名稱'],
             'desc':['E1',u'描述'],
             'est_bgn':['F1',u'預定開始'],
             'est_end':['G1',u'預定結束'],
             'res':['H1',u'人員'],
         },
     },
}
from tabledown.tdxls import TDXls
tdx = TDXls(mcc)
data = tdx.xls2dict(filename)
#pp.pprint(data['Sheet1']['tasks'][0])

sheet1=data['Sheet1']

master=sheet1['master']
tasks=sheet1['tasks']

master_keys = ('id','name','desc','billing','cust_pm','org','exec_pm','sa','pg')
task_keys = ('id','sno','type','name','desc','est_bgn','est_end','res')

write_file = False

# project data
mId, mName, mDesc, mBilling, mCustPm, mOrg, mPm, mSa, mPg = map(master.get, master_keys)
print mId, mName, mDesc, mBilling, mCustPm, mOrg, mPm, mSa, mPg
if not mId:
    # create project
    dProject={'workEffortName': mName, 'description': mDesc,
            'clientBillingPartyId': mBilling, 'organizationPartyId': mOrg,
            'scopeEnumId':'WES_PRIVATE',}
    br.open("%s/EditProject" % url_app)
    applyDict2Form(br, 'EditProject', dProject)
    res = br.submit()
    id, soup = page_get_project_id_and_soup(res.get_data())
    if not id and page_soup_error(soup): sys.exit(1) # error
    master['id'] = mId = id
    write_file=True

def assign_project_role(parties, role):
    role_ti={'ACC':'PROVIDER_ACCOUNTING', 
        'SA':'PROVIDER_ANALYST',
        'PG':'PROVIDER_FUNCTIONAL',
        'PM':'PROVIDER_MANAGER', 
        'TEST':'PROVIDER_TESTER',
        'QA':'PROVIDER_VALIDATOR'}.get(role, 'PROVIDER_FUNCTIONAL')
    for party in parties:
        try:
            br.open("%s/ListWorkEffortPartyAssigns?projectId=%s" % (url_app,mId))
            br.select_form(name='AddWorkEffortPartyAssign')
            br.form['partyId']=[party]
            res=br.submit()
            br.select_form(name='AddWorkEffortPartyAssign')
            br.form['roleTypeId']=[role_ti]
            res=br.submit()
            print "Party(%s) is assigned Role(%s)" % (party, role_ti)
        except:
            print "Party(%s) is not project team or Role(%s)" % (party, role_ti)
            continue

def assign_task_role(_wid, _res, _role):
    role_ti={'ACC':'PROVIDER_ACCOUNTING', 
        'SA':'PROVIDER_ANALYST',
        'PG':'PROVIDER_FUNCTIONAL',
        'PM':'PROVIDER_MANAGER', 
        'TEST':'PROVIDER_TESTER',
        'QA':'PROVIDER_VALIDATOR'}.get(_role, 'PROVIDER_FUNCTIONAL')
    try:
        br.open("%s/EditTaskPartyAssigns?workEffortId=%s" % (url_app,_wid))
        br.select_form(name='AddWorkEffortPartyAssign')
        br.form['partyId']=[_res]
        res=br.submit()
        br.select_form(name='AddWorkEffortPartyAssign')
        br.form['roleTypeId']=[role_ti]
        res=br.submit()
        print "  -> Add Role(%s): %s" % (role_ti, _res)
    except:
        print "  -> Party(%s) is not Role(%s)" % (_res, role_ti)

# add role to project
if mPm:
    pm_lst = mPm.split(',')
    assign_project_role(pm_lst, 'PM')
if mSa:
    sa_lst = mSa.split(',')
    assign_project_role(sa_lst, 'SA')
if mPg:
    pg_lst = mPg.split(',')
    assign_project_role(pg_lst, 'PG')

def getRole(res):
    if res in pm_lst: return 'PM'
    elif res in sa_lst: return 'SA'
    elif res in pg_lst: return 'PG'
    return None

phase_id = task_id = None
phase_sno = task_sno = -1

def page_get_phase_id_and_soup(page):
    soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
    id = None
    try:
        ff = soup.find('form',{'id':'AddPhase'})
        ii_sno1 = ff.find('input',{'name':'sequenceNum'})
        sno = int(ii_sno1.attrMap['value'])
        ii_sno2 = soup.findAll('input',{'name':'sequenceNum','value':sno})[-1]
        ff = ii_sno2.findPrevious('form')
        ii_id = ff.find('input',{'name':'workEffortId'})
        id = int(ii_id.attrMap['value'])
    except: pass
    print "---> new phase id %s" % id
    return (id, soup)

def page_get_task_id_and_soup(page, pno, sno):
    soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
    id = None
    try:
        # 1st find phase 
        op = soup.find('option',{"selected":"selected","value":pno})
        op_tr = op.findPrevious('tr')
        while op_tr:
            op_sno = op_tr.find('input',{'name':'sequenceNum','value':sno})
            if op_sno: # found matched            
                ff = op_sno.findPrevious('form')
                ii_id = ff.find('input',{'name':'workEffortId'})
                id = int(ii_id.attrMap['value'])
                break
            else: op_tr = op_tr.findNextSibling()
    except: pass
    print "---> new task id %s" % id
    return (id, soup)

for task in tasks:
    # phase/task data
    eId, eSno, eType, eName, eDesc, eEstBgn, eEstEnd, eRes = map(task.get, task_keys)
    is_new = ''
    if not eId:
        if eType=='P': # create phase
            if eSno: phase_sno=int(eSno)
            else:
                if phase_sno==-1: phase_sno = 100
                else: phase_sno += 100
                eSno=task['sno']=str(phase_sno)
            dPhase={'sequenceNum':str(phase_sno),
                'workEffortName':eName,
                'description':eDesc}
            br.open("%s/FindPhase?projectId=%s" % (url_app, mId))
            applyDict2Form(br, 'AddPhase', dPhase)
            res = br.submit()
            id, soup = page_get_phase_id_and_soup(res.get_data())
            if not id and page_soup_error(soup):
                print "! No id return"
                break # error
            eId = task['id'] = phase_id = id
            task_sno = -1
            is_new='*'
        elif eType=='T': # create task
            if eSno: task_sno=int(eSno)
            else:
                if task_sno==-1: task_sno = 10
                else: task_sno += 10
                eSno=task['sno']=str(task_sno)
            dTask={'workEffortParentId':str(phase_id),
                'sequenceNum':str(task_sno),
                'workEffortName':eName,
                'description':eDesc,
                'estimatedStartDate':eEstBgn,
                'estimatedCompletionDate':eEstEnd}
            br.open("%s/EditProjectTasks?projectId=%s" % (url_app, mId))
            applyDict2Form(br, 'EditTask', dTask)
            res = br.submit()
            id, soup = page_get_task_id_and_soup(res.get_data(), str(phase_id), str(task_sno))
            if not id and page_soup_error(soup):
                print "! No id return"
                break # error
            eId = task['id'] = id
            is_new='*'
            # add resources
            if eRes:
                for res in eRes.split(','):
                    role = getRole(res)
                    if role: assign_task_role(task['id'], res, role)
    print is_new, eId, eSno, eType, eName, eDesc, eEstBgn, eEstEnd, eRes

tdx.dict2xls(data['Sheet1'],re.sub(".xls", "-output.xls", filename))

